package udp

import (
	"encoding/json"
	"net"
	"sync"
	"time"

	"vdrift/internal/logger"
	"vdrift/internal/state"
)

const (
	HeartbeatInterval = 1 * time.Second
	HeartbeatPort     = 9650
	MulticastAddr     = "224.0.0.251:9650"
)

type Heartbeat struct {
	localState *state.LocalState
	nodeID     string
	ip         string
	seq        uint64
	mu         sync.Mutex
}

func NewHeartbeat(nodeID, ip string, localState *state.LocalState) *Heartbeat {
	return &Heartbeat{
		nodeID:     nodeID,
		ip:         ip,
		localState: localState,
		seq:        0,
		mu:         sync.Mutex{},
	}
}

func (h *Heartbeat) Start(stop <-chan struct{}) {
	h.mu.Lock()
	h.seq++
	h.mu.Unlock()

	addr, _ := net.ResolveUDPAddr("udp", MulticastAddr)
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		logger.Fatalf("failed to start UDP heartbeat: %v", err)
	}
	defer conn.Close()
	logger.Infof("UDP heartbeat started on %s", MulticastAddr)

	ticker := time.NewTicker(HeartbeatInterval)
	defer ticker.Stop()

	for {
		select {
		case <-stop:
			return
		case <-ticker.C:
			h.seq++
			payload := state.NodeState{
				NodeID:    h.nodeID,
				IP:        h.ip,
				Priority:  h.localState.CalculatePriority(),
				Healthy:   h.localState.FailedChecks == 0,
				Timestamp: time.Now(),
				Seq:       h.seq,
				VIPBound:  false, // 由选举决定
			}
			data, _ := json.Marshal(payload)
			conn.Write(data)
		}
	}
}

func (h *Heartbeat) GetSeq() uint64 {
	h.mu.Lock()
	defer h.mu.Unlock()
	return h.seq
}
